Fortran - Errors and error handling - Part 2
In the previous post we’ve looked at several ways to communicate to the user of a function that something could go wrong, or that maybe the function couldn’t produce the result that the user was looking for. In the case of an average function, we’d want to communicate to the user that in some cases the function can’t produce a meaningful result, namely if the array of numbers is empty. This isn’t really an error, it’s just that we don’t have a way to answer the question “what’s the average of this array?”. To communicate that with the function signature, we tried adding a “success” return value, making the calculated average an intent(out)
argument. The function modifies the variable passed by the user to contain the average value, but only if the array is not empty:
By Matthias Noback
read moreFortran - Errors and error handling - Part 1 - Exploration
Fortran doesn’t have exceptions. You can’t jump out of a function when something unexpected happens, then reflect on what happened outside the function, with the help of a try/catch block. As an alternative, intrinsic (built-in) procedures and constructs like write
, read
and open
allow you to pass an integer
variable as one of its arguments, to which it will assign a specific value indicating whether an error occurred. For example, when you try to open a file that doesn’t exist, you will get a non-zero value in the variable passed as the argument for iostat
:
By Matthias Noback
read moreFortran - Functional Programming Concepts - Reduce
We’ve implemented filter and map operations. The results of both these operations are new arrays. Yet another common operation on arrays is the so-called reduction operation; we “reduce” multiple values to a single value. The most obvious example is calculating the sum of an array of integers: the input is an array (or list) and the output is a single integer
:
pure function sum_all(numbers) result(res)
integer, dimension(:), intent(in) :: numbers
integer :: res
integer :: i
res = 0
do i = 1, size(numbers)
res = res + numbers(i)
end do
end function sum_all
Just like with filter
and map
we can imagine a generalization of this process, which involves looping over the array elements and building up a single return value along the way. We start with the existing sum_all
function. The first step is to let the user decide what the return value should be, which is the logic that happens inside the do
loop. We extract a function for this:
By Matthias Noback
read moreFortran - Functional Programming - List type
In the previous post we looked at this dream scenario:
list([1, 3, 5, 7]) % filter(divisible_by(3)) % map(square)
As mentioned, we can’t chain function calls like this. But we can put intermediate results in local variables and achieve something similar:
integers = list([1, 3, 5, 7])
divisible_by_3 = integers%filter(divisible_by(3))
squared = divisible_by_3%map(square)
If the intermediate values are all the same type, we can reuse the variable:
integers = list([1, 3, 5, 7])
integers = integers%filter(divisible_by(3))
integers = divisible_by_3%map(square)
To enable this syntax, it’s clear that we need to introduce a derived type for a list of integers that has type-bound procedures filter
and map
. These functions should each return a new list, so we can call any of these functions again on the new list. Let’s start with an integer_list_t
which contains an array of integers. We also provide a generic list
interface
with a specific procedure create_integer_list
for creating the integer_list_t
:
By Matthias Noback
read more